package rmmk.framework.datasources.abstracts;

import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import rmmk.datasources.parsing.ClassTypes;
import rmmk.framework.datasources.DocumentSetSelector;

/**
 * Klasa przechowująca kategorie dla wczytywanych dokumentów. Jest również
 * ponownie użyta do zapisania zklasyfikowanych kategorii
 * 
 * @author marcin
 * 
 */
public class DocumentCategories {
	private static Logger logger = LoggerFactory
			.getLogger(DocumentCategories.class);
	private List<String> TOPICS, PLACES, PEOPLE;// , ORGS = new
												// Vector<String>(), EXCHANGES =
												// new Vector<String>();

	public DocumentCategories() {
		TOPICS = new Vector<String>();
		PLACES = new Vector<String>();
		PEOPLE = new Vector<String>();
	}

	public DocumentCategories(DocumentCategories document) {
		this.PEOPLE = document.getPEOPLE();
		this.TOPICS = document.getTOPICS();
		this.PLACES = document.getPLACES();
	}

	public int countNumberOfLabels() {
		return this.TOPICS.size() + PLACES.size() + PEOPLE.size();
	}

	public List<String> getTOPICS() {
		return TOPICS;
	}

	public void setTOPICS(List<String> tOPICS) {
		TOPICS = tOPICS;
	}

	public List<String> getPLACES() {
		return PLACES;
	}

	public void setPLACES(List<String> pLACES) {
		PLACES = pLACES;
	}

	public List<String> getPEOPLE() {
		return PEOPLE;
	}

	public void setPEOPLE(List<String> pEOPLE) {
		PEOPLE = pEOPLE;
	}

	public boolean containsCategory(ClassTypes category) {
		switch (category) {
		case PEOPLE:
			if (this.PEOPLE.size() > 0)
				return true;
			break;
		case PLACES:
			if (this.PLACES.size() > 0)
				return true;
			break;
		case TOPICS:
			if (this.TOPICS.size() > 0)
				return true;
			break;
		}
		return false;
	}

	public boolean containsCategory(ClassTypes category, int limit) {
		if (limit < 1)
			return this.containsCategory(category);
		else {
			switch (category) {
			case PEOPLE:
				if (this.PEOPLE.size() > 0 && this.PEOPLE.size() <= limit)
					return true;
				break;
			case PLACES:
				if (this.PLACES.size() > 0 && this.PLACES.size() <= limit)
					return true;
				break;
			case TOPICS:
				if (this.TOPICS.size() > 0 && this.TOPICS.size() <= limit)
					return true;
				break;
			}
			return false;
		}
	}
	
	public boolean containsCategoryLowerLimit(ClassTypes category, int lowerLimit)
	{
		switch (category) {
		case PEOPLE:
			if (this.PEOPLE.size() > 0 && this.PEOPLE.size() >= lowerLimit)
				return true;
			break;
		case PLACES:
			if (this.PLACES.size() > 0 && this.PLACES.size() >= lowerLimit)
				return true;
			break;
		case TOPICS:
			if (this.TOPICS.size() > 0 && this.TOPICS.size() >= lowerLimit)
				return true;
			break;
		}
		return false;
	}

	public boolean containsCategory(ClassTypes category, int limit,
			List<String> avilableCategoryNames) {
		if (avilableCategoryNames.size() < 1)
			return this.containsCategory(category, limit);
		else {
			switch (category) {
			case PEOPLE:
				if (this.PEOPLE.size() > 0 && this.PEOPLE.size() <= limit
						&& isNamePermitted(avilableCategoryNames, this.PEOPLE))
					return true;
				break;
			case PLACES:
				if (this.PLACES.size() > 0 && this.PLACES.size() <= limit
						&& isNamePermitted(avilableCategoryNames, this.PLACES))
					return true;
				break;
			case TOPICS:
				if (this.TOPICS.size() > 0 && this.TOPICS.size() <= limit
						&& isNamePermitted(avilableCategoryNames, this.TOPICS))
					return true;
				break;
			}
			return false;
		}
	}

	private static int howMuch = 0;

	/*@Override
	public boolean equals(Object obj) {
		if (obj == null)
			logger.error("Dokument zaklasyfikowany jako null ! " + howMuch);

		if (obj instanceof DocumentCategories) {
			DocumentCategories doc = (DocumentCategories) obj;

			if (areVectorsTheSame(doc.getPEOPLE(), getPEOPLE())
					&& areVectorsTheSame(doc.getPLACES(), getPLACES())
					&& areVectorsTheSame(doc.getTOPICS(), getTOPICS()))
				return true;

		}

		return false;
	}*/
	
	@Override
	public boolean equals(Object docm) {
		if (docm == null)
			logger.error("Dokument zaklasyfikowany jako null ! " + howMuch);

		List<ClassTypes> clases = DocumentSetSelector.getDesiredCategories();
		
		if (docm instanceof DocumentCategories) {
			DocumentCategories doc = (DocumentCategories) docm;

			if(clases.contains(ClassTypes.PEOPLE) && this.PEOPLE.size() > 0)
			{
				for(String cat : doc.PEOPLE)
					if(!doesContain(this.PEOPLE, cat)) return false;
			}else if(clases.contains(ClassTypes.PLACES) && this.PLACES.size() > 0)
			{
				for(String cat : doc.PLACES)
					if(!doesContain(this.PLACES, cat)) return false;
			}else if(clases.contains(ClassTypes.TOPICS) && this.TOPICS.size() > 0)
			{
				for(String cat : doc.TOPICS)
					if(!doesContain(this.TOPICS, cat)) return false;
			}
			return true;
		}

		return false;
	}
	
	private boolean doesContain(List<String> categories, String find)
	{
		for(String s : categories)
			if(s.equals(find)) return true;
		return false;
	}

	boolean areVectorsTheSame(List<String> a, List<String> b) {
		if (a.size() == b.size()) {
			for (int i = 0; i < a.size(); ++i)
				if (!a.get(i).equals(b.get(i)))
					return false;
			return true;
		} else
			return false;
	}

	public boolean isNamePermitted(List<String> avilableCategoryNames,
			String name) {
		if (avilableCategoryNames.size() == 0)
			return true;

		for (String n : avilableCategoryNames)
			if (n.equals(name))
				return true;
		return false;
	}

	public boolean isNamePermitted(List<String> avilableCategoryNames,
			List<String> names) {
		if (avilableCategoryNames.size() == 0)
			return true;

		for (String name : names)
			if (isNamePermitted(avilableCategoryNames, name))
				return true;
		return false;
	}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();

		List<ClassTypes> clases = DocumentSetSelector.getDesiredCategories();

		List<List<String>> lists = new ArrayList<>(3);
		if (contains(clases, ClassTypes.PEOPLE))
			lists.add(PEOPLE);
		if (contains(clases, ClassTypes.PLACES))
			lists.add(PLACES);
		if (contains(clases, ClassTypes.TOPICS))
			lists.add(TOPICS);
		for (List<String> ll : lists)
			for (String s : ll)
				sb.append(s);

		return sb.toString();
	}

	private boolean contains(List<ClassTypes> list, ClassTypes desired) {
		for (ClassTypes ct : list)
			if (ct.equals(desired))
				return true;
		return false;
	}
}
